import threading
import requests
import simplejson
from util.common_func import SubSymbol, PubSymbol
from util.jiafu_log import JiaFuLogger
from util.const import *
# 导入django环境，确保recover_condition_order能使用ConditionOrder
import django
django.setup()
from condition_order.models import ConditionOrder
from django.db.models import Q
from django.db import close_old_connections
from condition_order.models import ConditionOrder

logger = JiaFuLogger("jiafu_server:condition_order:services:condition_order_logic")


class ConditionOrderThread(threading.Thread):

    # ToDo 后面考虑用celery任务调度策略实现条件单的发布和取消
    def __init__(self, cookies, condition_order_inst):
        threading.Thread.__init__(self)
        self.ord_inst = condition_order_inst  # django model instance
        self.cookies = cookies
        self.sub_symbol_channel = SubSymbol(self.ord_inst.symbol)
        self.keep_running = True
        # 这里不用条件单的cookie，用条件单的cookie去连ws，貌似会连接不上ws
        self.pub_symbol = PubSymbol()

    def run(self):
        try:
            self.pub_symbol.set_symbol_ws(self.ord_inst.symbol)
            self.ord_inst.order_status = ORDER_STATUS_RUNNING
            self.ord_inst.save()
            logger.info('run condition order, id; %d ' % self.ord_inst.condition_order_id)
            while self.keep_running:
                close_old_connections()
                order_status = ConditionOrder.objects.get(
                    condition_order_id=self.ord_inst.condition_order_id).order_status
                logger.info(f'order {self.ord_inst.condition_order_id} status {order_status}')
                if order_status == ORDER_STATUS_STOPPED:
                    logger.info('stop condition order, id; %d ' % self.ord_inst.condition_order_id)
                    break
                ws_need_reconnect, symbol_msg = self.sub_symbol_channel.get_message()
                if ws_need_reconnect:
                    self.pub_symbol.reconnect()
                elif symbol_msg:
                    self.__exec_order_logic(symbol_msg)
        except Exception:
            import traceback
            logger.error(traceback.format_exc())

    def stop_pub(self):
        self.pub_symbol.stop_pub(self.ord_inst.symbol)

    def create_order(self):
        logger.info('start create condition order, id; %d ' % self.ord_inst.condition_order_id)
        self.keep_running = False
        params = {"symbol": self.ord_inst.symbol, "type": ORDER_TYPE_LIMIT, "price": self.ord_inst.price,
                  "quantity": self.ord_inst.qty, "side": self.ord_inst.side,
                  "stop_price": self.ord_inst.condition_price}
        url = GZ_REST_BASE_URL + 'create_order/'
        res = requests.post(url, data=params, cookies=self.cookies, timeout=HTTP_TIMEOUT)
        if res.status_code == 200:
            data = simplejson.loads(res.text)
            if data['errno'] != 0:
                self.ord_inst.fail_reason = data["message"].encode('utf-8')
                self.ord_inst.order_status = ORDER_STATUS_FAILLED
                self.ord_inst.save()
            else:
                self.ord_inst.order_status = ORDER_STATUS_DONE
                self.ord_inst.save()
            return data
        else:
            return {"errno": -1, "msg": "unknown msg"}

    def __exec_order_logic(self, symbol_msg):
        # logger.debug('receive symbol msg: %s' % str(symbol_msg))
        if self.ord_inst.price_type == 0 and symbol_msg['type'] == 'trade':
            base_price = self.__get_cur_price(symbol_msg)
        elif self.ord_inst.price_type == 1 and symbol_msg['type'] == 'depth':
            base_price = self.__get_buy_1_price(symbol_msg)
        elif self.ord_inst.price_type == 2 and symbol_msg['type'] == 'depth':
            base_price = self.__get_sell_1_price(symbol_msg)
        elif self.ord_inst.price_type not in [0, 1, 2]:
            logger.error('not support this price type; %d' % self.ord_inst.price_type)
            self.keep_running = False
            return
        else:
            return
        if self.ord_inst.compare_type == 0:
            if base_price > self.ord_inst.condition_price:
                self.create_order()
        elif self.ord_inst.compare_type == 1:
            if base_price >= self.ord_inst.condition_price:
                self.create_order()
        elif self.ord_inst.compare_type == 2:
            if base_price < self.ord_inst.condition_price:
                self.create_order()
        elif self.ord_inst.compare_type == 3:
            if base_price <= self.ord_inst.condition_price:
                self.create_order()
        else:
            logger.error('not support this compare_type')
            self.keep_running = False
            return

    def __get_cur_price(self, symbol_msg):
        return float(symbol_msg['msg']['price'])

    def __get_buy_1_price(self, symbol_msg):
        bids = symbol_msg['msg']['bids']
        return float(bids[0][0])

    def __get_sell_1_price(self, symbol_msg):
        asks = symbol_msg['msg']['asks']
        return float(asks[0][0])


def recover_condition_order():
    orders = ConditionOrder.objects.filter(order_status=ORDER_STATUS_CREATE) | ConditionOrder.objects.filter(
        order_status=ORDER_STATUS_RUNNING)
    orders = orders.all()
    cots = []
    for od in orders:
        if od.cookies:
            cookies = simplejson.loads(od.cookies)
            cot = ConditionOrderThread(cookies, od)
            cots.append(cot)
            cot.start()
    return cots
